🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / testing / src / androidMain / kotlin / org / meshtastic / core / testing / RobolectricBleBonding.kt
Displaying Raw • Download
core/testing/src/androidMain/kotlin/org/meshtastic/core/testing/RobolectricBleBonding.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 4.65 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.testing
Tff7b72import T7ee787android.Manifest
Tff7b72import T7ee787android.app.Application
Tff7b72import T7ee787android.bluetooth.BluetoothAdapter
Tff7b72import T7ee787android.bluetooth.BluetoothDevice
Tff7b72import T7ee787android.content.Intent
Tff7b72import T7ee787android.os.Looper
Tff7b72import T7ee787org.robolectric.RuntimeEnvironment
Tff7b72import T7ee787org.robolectric.Shadows.shadowOf
Tff7b72import T7ee787org.robolectric.shadows.ShadowBluetoothDevice
T8b949e/**
* Reusable Robolectric helpers for driving Android Bluetooth bonding logic in `androidHostTest` source sets.
*
* These let a unit test exercise the real `AndroidBluetoothRepository.bond()` (and any future BLE bonding code) without
* an emulator and without a production seam. They rely on two Robolectric behaviors (verified against Robolectric
* 4.16.x):
* - [android.bluetooth.BluetoothAdapter.getRemoteDevice] caches the returned [BluetoothDevice] by address in a static
* map, so the shadow configured here is the *same* instance production code reads when it calls
* `getRemoteDevice(mac)` internally.
* - [ShadowBluetoothDevice.createBond] calls `checkForBluetoothConnectPermission()` first, so tests must call
* [grantBluetoothConnectPermission] or `createBond()` throws [SecurityException] instead of returning a value.
*
* Isolation note: because the device cache is static and survives across tests in the same JVM, give each test a
* distinct MAC so bond-state cannot bleed between tests.
*/
Tff7b72object T56d364RobolectricBleBonding Tb4b4b4{
T8b949e/** A syntactically valid BLE MAC for tests that don't care about the specific address. */
Tff7b72const Tff7b72val Te6edf3TEST_BLE_MACTb4b4b4: Tffa657String Tff7b72= Ta5d6ff"Ta5d6ffAA:BB:CC:DD:EE:FFTa5d6ff"
Tff7b72private Tff7b72val Te6edf3applicationTb4b4b4: Te6edf3Application
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3RuntimeEnvironmentTb4b4b4.Te6edf3getApplicationTb4b4b4(Tb4b4b4)
T8b949e/**
* The default adapter Robolectric exposes; production resolves the same one via
* [android.bluetooth.BluetoothManager].
*/
Tff7b72private Tff7b72val Te6edf3adapterTb4b4b4: Te6edf3BluetoothAdapter
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3BluetoothAdapterTb4b4b4.Te6edf3getDefaultAdapterTb4b4b4(Tb4b4b4)
T8b949e/** Grant the runtime permissions [ShadowBluetoothDevice.createBond] checks, so it returns instead of throwing. */
Tff7b72fun Td2a8ffgrantBluetoothConnectPermissionTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3shadowOfTb4b4b4(Te6edf3applicationTb4b4b4)
Tb4b4b4.Te6edf3grantPermissionsTb4b4b4(Te6edf3ManifestTb4b4b4.Te6edf3permissionTb4b4b4.Te6edf3BLUETOOTH_CONNECTTb4b4b4, Te6edf3ManifestTb4b4b4.Te6edf3permissionTb4b4b4.Te6edf3BLUETOOTH_SCANTb4b4b4)
Tb4b4b4}
T8b949e/**
* The (address-cached) [ShadowBluetoothDevice] for [mac] — the same instance production's `getRemoteDevice` sees.
*/
Tff7b72fun Td2a8ffdeviceShadowTb4b4b4(Te6edf3macTb4b4b4: Tffa657String Tff7b72= Te6edf3TEST_BLE_MACTb4b4b4)Tb4b4b4: Te6edf3ShadowBluetoothDevice Tff7b72= Te6edf3shadowOfTb4b4b4(Te6edf3adapterTb4b4b4.Te6edf3getRemoteDeviceTb4b4b4(Te6edf3macTb4b4b4)Tb4b4b4)
T8b949e/**
* Configure the cached device for [mac]: its [bondState] and what `createBond()` returns.
*
* Defaulting [createBondReturns] to `false` reproduces the #5849 entry condition (createBond() returned false →
* re-check bondState). Note Robolectric's `createBond()` sets bondState to BONDED only when [createBondReturns] is
* `true`; with `false` the [bondState] you set here is what the production re-check reads.
*/
Tff7b72fun Td2a8ffprimeBondTb4b4b4(
Te6edf3macTb4b4b4: Tffa657String Tff7b72= Te6edf3TEST_BLE_MACTb4b4b4,
Te6edf3bondStateTb4b4b4: Tffa657Int Tff7b72= Te6edf3BluetoothDeviceTb4b4b4.Te6edf3BOND_NONETb4b4b4,
Te6edf3createBondReturnsTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3ShadowBluetoothDevice Tff7b72= Te6edf3deviceShadowTb4b4b4(Te6edf3macTb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{
Te6edf3setBondStateTb4b4b4(Te6edf3bondStateTb4b4b4)
Te6edf3setCreatedBondTb4b4b4(Te6edf3createBondReturnsTb4b4b4)
Tb4b4b4}
T8b949e/**
* Broadcast `ACTION_BOND_STATE_CHANGED` for [mac] and pump the main looper so a runtime-registered
* [android.content.BroadcastReceiver] (e.g. the one `bond()` registers) is delivered synchronously.
*/
Tff7b72fun Td2a8ffsendBondStateChangedTb4b4b4(Te6edf3macTb4b4b4: Tffa657StringTb4b4b4, Te6edf3newStateTb4b4b4: Tffa657IntTb4b4b4, Te6edf3previousStateTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3intent Tff7b72=
Te6edf3IntentTb4b4b4(Te6edf3BluetoothDeviceTb4b4b4.Te6edf3ACTION_BOND_STATE_CHANGEDTb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{
Te6edf3putExtraTb4b4b4(Te6edf3BluetoothDeviceTb4b4b4.Te6edf3EXTRA_DEVICETb4b4b4, Te6edf3adapterTb4b4b4.Te6edf3getRemoteDeviceTb4b4b4(Te6edf3macTb4b4b4)Tb4b4b4)
Te6edf3putExtraTb4b4b4(Te6edf3BluetoothDeviceTb4b4b4.Te6edf3EXTRA_BOND_STATETb4b4b4, Te6edf3newStateTb4b4b4)
Te6edf3putExtraTb4b4b4(Te6edf3BluetoothDeviceTb4b4b4.Te6edf3EXTRA_PREVIOUS_BOND_STATETb4b4b4, Te6edf3previousStateTb4b4b4)
Tb4b4b4}
Te6edf3applicationTb4b4b4.Te6edf3sendBroadcastTb4b4b4(Te6edf3intentTb4b4b4)
Te6edf3shadowOfTb4b4b4(Te6edf3LooperTb4b4b4.Te6edf3getMainLooperTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4.Te6edf3idleTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.04s